using System;
using System.Collections;
using System.Text;

namespace GPU_NN
{
    public class Node
    {
        /// <summary>
        /// Default constructor for the node class with no initializations
        /// </summary>
        public Node()
        {
        }
        
        /// <summary>
        /// Node constructor used to create the number of nodes 
        /// read in from the XML file
        /// </summary>
        /// <param name="totalnodes"></param>
        public Node(int totalnodes)
        {
            // Initialize all variables
	        //m_finput = 0;
            inputArray = new ArrayList();
	        p_strType = "";
	        p_strFunction = "";
	        m_nID = -1;
            m_nNumofInputs = 0;
            finished = false;

            linkArray = new ArrayList();
        }

        /// <summary>
        /// Function Description: This method is used to set the type of node 
        ///         being created
        /// 
        /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public void SetNodeType(String type)
		{
			p_strType = type;
		}
		
		/// <summary>
        /// Function Description: This method is used to set the function of the
        ///         node that is being created
        /// 
        /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public void SetNodeFunction(String function)
		{
			p_strFunction = function;
		}
		
		/// <summary>
        /// Function Description: This method is used to set branch data for the 
        ///         node being created
        /// 
        /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public void SetNodeBranch(int branch)
		{
			m_nBranch = branch;
		}
	
		/// <summary>
        /// Function Description: This method is used to set the ID of the node
        /// 
        /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public void SetNodeID(int ID)
		{
			m_nID = ID;
		}
		
		/// <summary>
        /// Function Description: This method is used to add a link to a node
        ///         so you know where to send the data once the node has been
        ///         executed
        /// 
        /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public void SetNodeLink(Link link/*int target, int totalnodes*/)
		{
			linkArray.Add(link);
		}
		

        /// <summary>
        /// Function Description: This method is used to set the input value from
        ///         the links from other nodes.  this is used to fill the data 
        ///         input to each node
        /// 
        /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public void UpdateInputValue(double value)
		{
			// Inputs the value of the input link
			inputArray.Add(value);
		}

		/// <summary>
        /// Function Description: This method is used to set the inputs of the 
        ///         node.  this is a label name for the inputs in the start of the
        ///         NN
        /// 
        /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public void SetNodeInput(String input)
		{
			p_strInputName = input;
		}
		
		/// <summary>
        /// Function Description: This method is used to return the ID of a node
        /// 
        /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public int GetNodeID()
		{
			return m_nID;
		}
		
		/// <summary>
        /// Function Description: This method is used to return the type of node
        ///         in a string format
        /// 
        /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public String GetNodeType()
		{
			return p_strType;
		}
		
		/// <summary>
        /// Function Description: This method is used to calculate the output of
        ///         a node depending on the function of the node
        /// 
        /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public double GetNodeOutput()
		{
			// Need to call GPU functions still need algorithm
			double input = 0;
			Link[] outputs = new Link[linkArray.Count];
			double output = 0.0;

			linkArray.CopyTo(outputs);
			if (p_strFunction == "identity(x)")
			{
				// run identity function on all inputs
				// sum all inputs
				input = SumInputs();
				// perform the identity and send to output
				output = input;
			}
			else if (p_strFunction == "sin(x)")
			{
				// run sin function on all inputs
				// sum all inputs
				input = SumInputs();
				output = Math.Sin(input);
			}
			else if (p_strFunction == "cos(x)")
			{
				// run cos function on all inputs
				// sum all inputs
				input = SumInputs();
				output = Math.Cos(input);
			}
			else if (p_strFunction == "sigmoid(x)")
			{
				// run sigmoid function on all inputs
				// sum all inputs
				input = SumInputs();
				output = (1 / (1 + Math.Exp(-input)));
			}
			else if (p_strFunction == "gaussian(x)")
			{
				// run gaussian function on all inputs
				// sum all inputs
				input = SumInputs();
				Random a = new Random();
				// this is the height of the standard gaussian curve
				double rand = /*a.NextDouble() */ 2;

				// this is the width of the standard gaussian curve
				double width = /*a.NextDouble() */ 1.75;

				output = rand * Math.Exp(-(input * input) / (2.0 * ((width / 2.354) * (width / 2.354))));
			}

			return output;
		}
		
		/// <summary>
        /// Function Description: This method is used to return the output links
        ///         of a node in a list format
        /// 
        /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public ArrayList GetNodeLinkList()
		{
			return linkArray;
		}
		
		/// <summary>
        /// Function Description: This method is used to assign the initial inputs
        ///         to the NN that is the x, y, bias, and d
        /// 
        /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public String GetInputName()
		{
			return p_strInputName;
		}
		
		/// <summary>
        /// Function Description: This method is used to sum all the inputs into
        ///         a node prior to using the activation function
        /// 
        /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public double SumInputs()
		{
			double input = 0;
			double[] inputs = new double[inputArray.Count];
			inputArray.CopyTo(inputs);
            
            for (int i = 0; i < inputArray.Count; i++)
            {
                // add all the inputs
                input = input + inputs[i];
            }
            return input;
        }

        /// <summary>
        /// need a value to know the input like x, y, bias, and d
        /// </summary>
        String p_strInputName;
	    
        /// <summary>
        /// array of values input into the node
        /// </summary>
        public ArrayList inputArray;
        
        /// <summary>
        /// number of inputs, this needs to be the count of the
        /// inputArray prior to the run of the node function
        /// </summary>
        public int m_nNumofInputs;
        
	    /// <summary>
        /// type of the node input, hidden or output
	    /// </summary>
        String p_strType;
	    
	    /// <summary>
        /// activation function of the node
	    /// </summary>
        String p_strFunction;
	   
	    /// <summary>
        /// node id used primarily to find the node in question
	    /// </summary>
        int m_nID;

	    /// <summary>
        /// branch number of the node
	    /// </summary>
        int m_nBranch;

        /// <summary>
        /// array of links that this nodes has coming out of it
        /// </summary>
        ArrayList linkArray;

        
        /// <summary>
        /// if finished processing node, lets you know the node
        /// has finished processing
        /// </summary>
        public bool finished;
    }
}
